/*************************************************************************
 * Filename:    ProcessQueue.c
 * Description: A process queue. Uses a generic queue and manages static
 *              memory for queue_items.
 * Group 3:     nachOS
 * Authors:     Daniel Fairweather
 *              
 * Class:       CSE 325
 * Instructor:  Mr. Duggan
 * Assignment:  Lab #1 Queue Manager
 * Assigned:    January 22, 2013
 * Due:         January 29, 2013
 *************************************************************************/

#define NUM_REGS 3
#define MAX_PROCESSES 20
#include "Queue.h"

struct process_control_block{
    int pid;             // Process ID
    int psw;             // Program status word
    int page_table;      // Pagetable info
    int regs[NUM_REGS];  // Array of registers
};

struct process_control_block processes[MAX_PROCESSES];
queue process_queue;
queue_item items[MAX_PROCESSES];
queue_item* freespace;



/**
 * Initializes the queue
 * @author Daniel Fairweather
 */
void init(){
    int i = 0; // Incrementor for looping
    
    freespace = &items[0];
    
    // Link the reserved queue_items together, forming the freespace linked list
    for(i = 0; i < MAX_PROCESSES; i++){
        if(i != MAX_PROCESSES - 1){
            items[i].next = &items[i+1];
        }
        else{
            items[i].next = 0;
        }
        items[i].payload = &processes[i]; // Point the payload to it's corresponding process
    }
    
    // Mark the queue as empty
    process_queue.length = 0;
    process_queue.head = 0;
}



/**
 * Creates a process and enqueues it to the process_queue
 * @author Daniel Fairweather
 * @param pid The process id of the new process
 * @param psw The program status word of the new process
 * @param page_table The pagetable info of the new process
 * @returns int 1 on success, -1 on error (process_queue is full)
 */
int enqueueProcess(int pid, int psw, int page_table, int regs[]){
    struct process_control_block* process;
    queue_item* item;
    int i = 0;
    
    // Check if there is an available queue_item
    if(freespace != 0){
        item = freespace;
        process = item->payload;
        
        // Create process
        process->pid = pid;
        process->psw = psw;
        process->page_table = page_table;
        for(i = 0; i < NUM_REGS; i++){
            process->regs[i] = regs[i];
        }
        
        // Rearrange pointers
        freespace = item->next;
        
        enqueue(&process_queue, item);
        return(1);
    }
    else{
        return(-1); // Queue is full
    }
}


/**
 * Dequeues the oldest queue_item in the process_queue.
 * @author Daniel Fairweather
 * @returns int 1 on success, -1 on error (empty queue)
 */
int dequeueProcess(){
    queue_item* temp = process_queue.head; // The item to be dequeued
    struct process_control_block* payload;
    
    // Only dequeue an item if there is something to dequeue
    if(process_queue.length > 0){
        dequeue(&process_queue); // Dequeue the item
        
        // Add the dequeued item to freespace
        temp->next = freespace;
        freespace = temp;
        
        payload = temp->payload;
        return(payload->pid);
    }
    else{
        return(-1);
    }
}



/**
 * Deletes the process with the specified pid from the queue
 * @author Daniel Fairweather
 * @param pid The process id of the process to be deleted
 * @returns int The pid on success, -1 on error (No such process found)
 */
int deleteProcess(int pid){
    int i = 0;
    queue_item* temp = process_queue.head;
    struct process_control_block* payload;
    
    // Search for the specified pid
    for(i = 0; i < process_queue.length; i++){
        payload = temp->payload;
        // If found, remove from memory
        if(payload->pid == pid){
            delete(&process_queue, temp);
            
            // Return the memory back to freespace
            temp->next = freespace;
            freespace = temp;
            
            return(pid);
        }
        temp = temp->next;
    }
    
    return(-1);
}